package model

import (
	"context"
	"database/sql"
	"fmt"
	"portal/internal/common"
	"portal/internal/errorx"
	"portal/internal/types"
	"strconv"

	"github.com/Masterminds/squirrel"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

var _ SysDeptModel = (*customSysDeptModel)(nil)

type (
	// SysDeptModel is an interface to be customized, add more methods here,
	// and implement the added methods in customSysDeptModel.
	SysDeptModel interface {
		sysDeptModel
		withSession(session sqlx.Session) SysDeptModel
		InsertGetId(ctx context.Context, session sqlx.Session, data *SysDept)(int64,error)
		GetIdsByRoleIds(ctx context.Context, session sqlx.Session, roleIds []*int64) ([]*int64, error)
		GetListAuto(ctx context.Context,session sqlx.Session,roleId int64, cond *types.ListDeptRequest)([]*SysDept,error)
		GetListBase(ctx context.Context,session sqlx.Session,deptId int64,isJust bool)([]*SysDept,error)
		GetList(ctx context.Context, session sqlx.Session, cond *types.ListDeptRequest) ([]*SysDept, error)
		GetOneByPAON(ctx context.Context, session sqlx.Session, parentId int64, orderNum int64)(*SysDept,error)
		ExistByDIdRIds(ctx context.Context,session sqlx.Session,deptId int64,roleIds []*int64)(error)
		CountByParentId(ctx context.Context, session sqlx.Session, parentId int64)(*int64,error)
		DeleteByIds(ctx context.Context,session sqlx.Session,deptIds []*int64)(error)
		Edit(ctx context.Context, session sqlx.Session, data *SysDept)error
	}

	customSysDeptModel struct {
		*defaultSysDeptModel
	}
)

// NewSysDeptModel returns a model for the database table.
func NewSysDeptModel(conn sqlx.SqlConn) SysDeptModel {
	return &customSysDeptModel{
		defaultSysDeptModel: newSysDeptModel(conn),
	}
}

func (m *customSysDeptModel) withSession(session sqlx.Session) SysDeptModel {
	return NewSysDeptModel(sqlx.NewSqlConnFromSession(session))
}

func (m *customSysDeptModel) GetIdsByRoleIds(ctx context.Context, session sqlx.Session, roleIds []*int64) ([]*int64, error) {
	sb := squirrel.Select("dept_id").Distinct().
		From("sys_role_dept").
		Where(squirrel.Eq{"role_id": roleIds})
	query, args, err := sb.ToSql()
	if err != nil {
		return nil, err
	}
	var ids []*int64
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &ids, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &ids, query, args...)
	}
	return ids, err
}

func (m *customSysDeptModel) GetList(ctx context.Context, session sqlx.Session, cond *types.ListDeptRequest) ([]*SysDept, error) {
	sb := squirrel.Select("*").From(m.table)
	if len(cond.DeptName) > 0 {
		sb = sb.Where(squirrel.Like{"dept_name": "%" + cond.DeptName + "%"})
	}
	if len(cond.Status) > 0 {
		sb = sb.Where(squirrel.Eq{"status":cond.Status})
	}
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var dept []*SysDept
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &dept, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &dept, query, args...)
	}
	return dept, err
}

func (m *customSysDeptModel)GetListAuto(ctx context.Context,session sqlx.Session,roleId int64, cond *types.ListDeptRequest)([]*SysDept,error){
	sb := squirrel.Select("d.*").From("sys_role_dept rd")
	innerJoin := "sys_dept d on d.dept_id = rd.dept_id"
	if len(cond.DeptName) > 0 {
		innerJoin += fmt.Sprintf(" and d.dept_name like %%s%",cond.DeptName)
	}
	if len(cond.Status) > 0{
		innerJoin += fmt.Sprintf(" and d.status = %s",cond.Status)
	}

	sb = sb.InnerJoin(innerJoin).Where(squirrel.Eq{"rd.role_id":roleId})
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var dept []*SysDept
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &dept, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &dept, query, args...)
	}
	return dept, err
}
func (m *customSysDeptModel)GetListBase(ctx context.Context,session sqlx.Session,deptId int64,isJust bool)([]*SysDept,error){
	sb := squirrel.Select("d.*").From("sys_dept d")
	strDeptId := strconv.Itoa(int(deptId))
	orCond := make([]squirrel.Sqlizer,0)
	if !isJust {
		orCond = append(orCond, squirrel.Like{"ancestors":`%,`+ strDeptId},
		squirrel.Like{"ancestors":`%,` + strDeptId + `,%`},
		squirrel.Like{"ancestors": strDeptId + `,%`},
		squirrel.Eq{"ancestors":strDeptId})
	}
	orCond = append(orCond, squirrel.Eq{"dept_id":strDeptId})
	sb = sb.Where(squirrel.Or(orCond))
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var dept []*SysDept
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &dept, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &dept, query, args...)
	}
	return dept, err
}

func (m *customSysDeptModel)GetOneByPAON(ctx context.Context, session sqlx.Session, parentId int64, orderNum int64)(*SysDept,error){
	sb := squirrel.Select("*").From(m.table).
			Where(squirrel.Eq{"parent_id":parentId}).
			Where(squirrel.Eq{"order_num":orderNum})
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var dept SysDept
	if session != nil {
		err = session.QueryRowPartialCtx(ctx, &dept, query, args...)
	} else {
		err = m.conn.QueryRowPartialCtx(ctx, &dept, query, args...)
	}
	return &dept, err
}

func (m *customSysDeptModel)CountByParentId(ctx context.Context, session sqlx.Session, parentId int64)(*int64,error){
	sb := squirrel.Select("count(1)").From(m.table).
			Where(squirrel.Eq{"parent_id":parentId})
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var count int64
	if session != nil {
		err = session.QueryRowPartialCtx(ctx, &count, query, args...)
	} else {
		err = m.conn.QueryRowPartialCtx(ctx, &count, query, args...)
	}
	return &count, err
}

func (m *customSysDeptModel)ExistByDIdRIds(ctx context.Context,session sqlx.Session,deptId int64,roleIds []*int64)(error){
	sb := squirrel.Select("1").From("sys_role_dept").
			Where(squirrel.Eq{"dept_id":deptId}).
			Where(squirrel.Eq{"role_id":roleIds}).
			Limit(1)
	query,args,err := sb.ToSql()
	if err != nil {
		return err
	}
	var count int64
	if session != nil {
		err = session.QueryRowPartialCtx(ctx, &count, query, args...)
	} else {
		err = m.conn.QueryRowPartialCtx(ctx, &count,query, args...)
	}
	if err != nil || count <= 0 {
		return errorx.SqlExistError
	}
	return nil
}

func (m *customSysDeptModel)DeleteByIds(ctx context.Context,session sqlx.Session,deptIds []*int64)(error){
	ub := squirrel.Update(m.table).Set("del_flag",common.DELETED_FLAG).
			Where(squirrel.Eq{"dept_id":deptIds})
	query,args,err := ub.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_,err = session.ExecCtx(ctx, query, args...)
	} else {
		_,err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysDeptModel)InsertGetId(ctx context.Context, session sqlx.Session, data *SysDept)(int64,error){
	query, args, err := squirrel.Insert(m.table).Columns(sysDeptInsertRows).
		Values(data.ParentId,data.Ancestors,data.DeptName,data.OrderNum,data.Leader,data.Phone,data.Email,data.Status,data.DelFlag,data.CreateBy,data.CreateTime,data.UpdateBy,data.UpdateTime).
		ToSql()
	if err != nil {
		return 0, err
	}
	var sqlRes sql.Result
	if session != nil {
		sqlRes,err = session.ExecCtx(ctx, query, args...)
	} else {
		sqlRes,err = m.conn.ExecCtx(ctx, query, args...)
	}
	if err != nil {
		return 0, err
	}
	id,err := sqlRes.LastInsertId()
	return id, err
}

func (m *customSysDeptModel)Edit(ctx context.Context, session sqlx.Session, data *SysDept)error{	
	
	query,args,err := squirrel.Update(m.table).
		SetMap(
			squirrel.Eq{
				"ancestors":data.Ancestors,
				"update_by":data.UpdateBy,
				"update_time":data.UpdateTime,
				"del_flag":data.DelFlag,
				"email":data.Email,
				"leader":data.Leader,
				"order_num":data.OrderNum,
				"parent_id":data.ParentId,
				"status":data.Status,
				"phone":data.Phone,
				"dept_name":data.DeptName,
			}).
		Where(squirrel.Eq{"dept_id":data.DeptId}).
		ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_,err = session.ExecCtx(ctx, query, args...)
	} else {
		_,err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}